#import "SFUEventCollection.h"

/**
 * An SFUEventCollection is an object representing a
 * temporary collection of SFU events.
 *
 * @author      James Lin
 * @version     0.6.6
 * @since       0.0.1
 */
@implementation SFUEventCollection

/**
 * Initialize the SFUEventCollection as an empty collection.
 *
 * @return  the initialized empty SFUEventCollection
 */
- (id)init {
	if (self = [super init]) {
		eventDictionary = [[NSMutableDictionary alloc] init];
	}
	return self;
}

/**
 * Initialize the SFUEventCollection with an array of SFU events.
 * 
 * @precondition  the events are all valid and unique
 * @param events  the array of events with which to initialize
 * @return        the initialized SFUEventCollection with specified events
 */
- (id)initWithEvents:(NSArray*)events {
	if (self = [super init]) {
		eventDictionary = [[NSMutableDictionary alloc] init];
		[self addEvents:events];
	}
	return self;
}

/**
 * Add an SFU event to the collection.
 * 
 * @precondition  the event is unique in the collection
 * @param event   the event to add
 */
- (void)addEvent:(SFUEvent*)event {
	[eventDictionary setObject:event forKey:[event getKey]];
}

/**
 * Add an array of SFU events to the collection.
 *
 * @precondition  the events are all unique in the collection
 * @param events  the array of events to add
 */
- (void)addEvents:(NSArray*)events {
	for (NSObject* event in events) {
		[self addEvent:(SFUEvent*)event];
	}
}

/**
 * Add another SFU event collection to this collection.
 *
 * @param eventCollection  the event collection to add to this collection
 */
- (void)addEventCollection:(SFUEventCollection*)eventCollection {
	[self addEvents:[eventCollection getEvents]];
}
 
/**
 * Determine whether the given SFU event is in the collection.
 *
 * @param event  the event of which to check existence
 * @return       YES if the event is in the collection;
 *               NO otherwise.
 */
- (BOOL)containsEvent:(SFUEvent*)event {
	return ([[eventDictionary allKeysForObject:event] count] != 0);
}

/**
 * Retrieve size of collection.
 *
 * @return  the size of the collection as an integer
 */
- (int)size {
	return [eventDictionary count];
}

/**
 * Retrieve all SFU events in the collection.
 *
 * @return  an array of all SFU events in the collection
 */
- (NSArray*)getEvents {
	return [eventDictionary allValues];
}

/**
 * Find all SFU events whose heading or category contains
 * any keyword in the given space-delimited keyword string.
 *
 * @precondition   keyword string is not nil
 * @param keyword  the case-insensitive search keyword string
 * @return         an array of SFU events with suitable matches
 */
- (NSArray*)findEventsWithKeywordString:(NSString*)keyword {
	return [self findEventsWithKeywords:[keyword componentsSeparatedByString:@" "] 
					   matchAllKeywords:NO];
}

/**
 * Find all SFU events whose heading or category contains
 * any or all of the keywords in the given keyword list.
 *
 * If matching by any keyword in the keyword list, an additional sort
 * will be performed on the resulting list after the completed query.
 * The resulting list of events will be in non-increasing order of 
 * the number of keywords matched.
 *
 * @precondition    keywords are not nil
 * @param keywords  the list of case-insensitive search keywords
 * @param matchAll  YES if all keywords in the keyword list must match;
 *                  NO if any keyword can match.
 * @return          an array of SFU events with suitable matches
 */
- (NSArray*)findEventsWithKeywords:(NSArray*)keywords 
				  matchAllKeywords:(BOOL)matchAll {
	NSMutableArray* matchedEvents = [NSMutableArray array];
	
	if (matchAll) { // Match all keywords search mode
		for (NSString* key in [eventDictionary allKeys]) { // Search each event
			BOOL matched = YES;
			
			for (NSString* keyword in keywords) {
				// Attempt to match each keyword to the selected event
				if (keyword != nil && [key rangeOfString:keyword 
												 options:NSCaseInsensitiveSearch].length == 0) {
					// Keyword not matched
					matched = NO;
					break;
				}
			}
			
			if (matched) { // Event matched all keywords
				[matchedEvents addObject:[eventDictionary valueForKey:key]];
			}
		}
		return matchedEvents;
		
	} else { // Match any keywords search mode
		for (NSString* key in [eventDictionary allKeys]) { // Search each event
			int keywordCount = 0;
			
			for (NSString* keyword in keywords) {
				// Attempt to match each keyword to the selected event
				if ([key rangeOfString:keyword 
							   options:NSCaseInsensitiveSearch].length > 0) {
					keywordCount++;
				}
			}
			
			if (keywordCount > 0) { // Event matched at least one keyword
				((SFUEvent*)[eventDictionary valueForKey:key]).numKeywordsMatched = keywordCount;
				[matchedEvents addObject:[eventDictionary valueForKey:key]];
			}
		}
		
		NSSortDescriptor* sortDesc = [[[NSSortDescriptor alloc] initWithKey:@"numKeywordsMatched" 
																  ascending:NO] autorelease];
		NSArray *sortDescs = [NSArray arrayWithObject:sortDesc];
		return [matchedEvents sortedArrayUsingDescriptors:sortDescs];
	}
}

/**
 * Remove an SFU event from the collection.
 *
 * @param event  the event to remove
 */
- (void)removeEvent:(SFUEvent*)event {
	if (event != nil) {
		[eventDictionary removeObjectForKey:[event getKey]];
	}
}

/**
 * Empty the collection.
 */
- (void)clear {
	[eventDictionary removeAllObjects];
}

/**
 * Deallocate the collection.
 */
- (void)dealloc {
	[eventDictionary release];
	[super dealloc];
}

@end
